﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using CoreEx.Common.Extensions;
using CoreEx.Database.Query;
using CoreEx.DynamicInvoker;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using LinFu.Reflection;

namespace CoreEx.Database.Linq
{
    public abstract class QueryProviderBase : IQueryProvider, IInitialize<IServiceRequestResult>
    {
        protected string ConnectionName { get; set; }
        protected IServiceContainer ServiceContainer { get; set; }
        public ITranslateResult_old TranslateResult { get; protected set; }
        public IExpressionTranslator_old ExpressionTranslator { get; set; }
        public IExecutor Executor { get; set; }
        public IMaterializer Materializer { get; set; }
        public IRelationMapper RelationMapper { get; set; }

        protected abstract object Execute(Expression expression);

        #region IQueryProvider Members

        IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
        {
            return ServiceContainer.GetService<ITable<TElement>>(ConnectionName, expression, this);
        }

        IQueryable IQueryProvider.CreateQuery(Expression expression)
        {
            var methodInfo = typeof(IQueryProvider).GetMethods()
                .Where(m => m.Name == "CreateQuery" && m.GetGenericArguments().Count() > 0).First();
            return (IQueryable)methodInfo.DynamicInvoke(this, expression);
        }

        TResult IQueryProvider.Execute<TResult>(Expression expression)
        {                        
            var result = Execute(expression);
            if (typeof(TResult).IsEnumerable())
                return (TResult)result;
            return ((IEnumerable<TResult>) result).First();
            
        }

        object IQueryProvider.Execute(Expression expression)
        {          
            return Execute(expression);
        }

        #endregion

        #region IInitialize<IServiceRequestResult> Members

        public virtual void Initialize(IServiceRequestResult source)
        {
            ServiceContainer = source.Container;
            ConnectionName = source.ServiceName;
            ExpressionTranslator = ServiceContainer.GetService<IExpressionTranslator_old>(ConnectionName);
            Executor = ServiceContainer.GetService<IExecutor>();
            Materializer = ServiceContainer.GetService<IMaterializer>("ObjectMaterializer");
            RelationMapper = ServiceContainer.GetService<IRelationMapper>();
        }

        #endregion
    }
}
